/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.rbac.rpc;

import cn.hutool.core.date.DateUtil;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.je.auth.AuthLoginManager;
import com.je.common.base.DynaBean;
import com.je.common.base.service.MetaService;
import com.je.common.base.util.DateUtils;
import com.je.common.base.util.TreeUtil;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.rbac.exception.AccountException;
import com.je.rbac.service.IconType;
import com.je.rbac.service.account.RbacAccountService;
import org.apache.servicecomb.provider.pojo.RpcSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@RpcSchema(schemaId = "accountRpcService")
public class AccountRpcServiceImpl implements AccountRpcService {

    @Autowired
    private MetaService metaService;
    @Autowired
    private AuthLoginManager authLoginManager;
    @Autowired
    private RbacAccountService rbacAccountService;

    @Override
    public DynaBean findAccountById(String id) {
        return metaService.selectOne("JE_RBAC_ACCOUNT", ConditionsWrapper.builder().eq("JE_RBAC_ACCOUNT_ID", id));
    }

    @Override
    public DynaBean findAccountByPhone(String account) {
        return metaService.selectOne("JE_RBAC_ACCOUNT", ConditionsWrapper.builder().eq("ACCOUNT_PHONE", account));
    }

    @Override
    public List<DynaBean> findAllTenantAccount(String type, String account) {
        List<String> fieldList = buildAccountFieldByType(type);
        ConditionsWrapper wrapper = ConditionsWrapper.builder();
        wrapper.ne("SY_TENANT_ID", "global");
        wrapper.and(!fieldList.isEmpty(), inWrapper -> {
            for (int i = 0; i < fieldList.size(); i++) {
                if (i != 0) {
                    inWrapper.or();
                }
                inWrapper.eq(fieldList.get(i), account);
            }
        });
        return metaService.select("JE_RBAC_ACCOUNT", wrapper);
    }

    @Override
    public DynaBean findTenantAccount(String type, String tenantId, String account) {
        List<String> fieldList = buildAccountFieldByType(type);
        ConditionsWrapper wrapper = ConditionsWrapper.builder();
        wrapper.eq("SY_TENANT_ID", tenantId);
        wrapper.and(!fieldList.isEmpty(), inWrapper -> {
            for (int i = 0; i < fieldList.size(); i++) {
                if (i != 0) {
                    inWrapper.or();
                }
                inWrapper.eq(fieldList.get(i), account);
            }
        });
        return metaService.selectOne("JE_RBAC_ACCOUNT", wrapper);
    }

    @Override
    public DynaBean findAccountByType(String type, String account) {
        List<String> fieldList = buildAccountFieldByType(type);
        ConditionsWrapper wrapper = ConditionsWrapper.builder();
        for (int i = 0; i < fieldList.size(); i++) {
            if (i != 0) {
                wrapper.or();
            }
            wrapper.eq(fieldList.get(i), account);
        }
        return metaService.selectOne("JE_RBAC_ACCOUNT", wrapper);
    }

    @Override
    public DynaBean findLoginAccountByType(String type, String account) throws AccountException {
        List<String> fieldList = buildAccountFieldByType(type);
        ConditionsWrapper wrapper = ConditionsWrapper.builder();
        for (int i = 0; i < fieldList.size(); i++) {
            if (i != 0) {
                wrapper.or();
            }
            wrapper.eq(fieldList.get(i), account);
        }
        List<DynaBean> accountResult = metaService.select("JE_RBAC_ACCOUNT", wrapper);
        if (accountResult != null && accountResult.size() > 1) {
            throw new AccountException("用户名重复，请使用其他方式登录！");
        }
        return accountResult == null || accountResult.isEmpty() ? null : accountResult.get(0);
    }

    /**
     * 根据类型构建账号字段
     *
     * @param type
     * @return
     */
    private List<String> buildAccountFieldByType(String type) {
        List<String> splitedTypeList = Splitter.on(",").splitToList(type);
        List<String> fieldList = new ArrayList<>();
        if (splitedTypeList.contains("PHONE")) {
            fieldList.add("ACCOUNT_PHONE");
        }
        if (splitedTypeList.contains("USERNAME")) {
            fieldList.add("ACCOUNT_NAME");
        }
        if (splitedTypeList.contains("ACCOUNT")) {
            fieldList.add("ACCOUNT_CODE");
        }
        if (splitedTypeList.contains("EMAIL")) {
            fieldList.add("ACCOUNT_MAIL");
        }
        return fieldList;
    }

    @Override
    public List<DynaBean> findAccountByAssociationId(String associationId) {
        return metaService.select("JE_RBAC_ACCOUNT", ConditionsWrapper.builder().eq("JE_RBAC_ORG_ID", associationId));
    }

    @Override
    public List<DynaBean> findAccountByCompanyId(String companyId) {

        return null;
    }


    @Override
    public boolean checkDisable(String accountId) {
        DynaBean accountBean = findAccountById(accountId);
        return "1".equals(accountBean.getStr("SY_STATUS")) && authLoginManager.isDisable(accountId);
    }


    @Override
    public boolean isExpire(String id) throws AccountException {
        DynaBean accountBean = findAccountById(id);
        if (accountBean == null) {
            throw new AccountException("Can't find the account by id");
        }
        String expireTime = accountBean.getStr("ACCOUNT_EXPIRE_TIME");
        Date date = DateUtil.parseDateTime(expireTime);
        Date now = new Date();
        if (date.before(now)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean isLocked(String id) throws AccountException {
        DynaBean accountBean = findAccountById(id);
        if (accountBean == null) {
            throw new AccountException("Can't find the account by id");
        }
        return "1".equals(accountBean.getStr("ACCOUNT_LOCKED_CODE"));
    }

    /**
     * 获取增加或移除的id
     *
     * @param type
     * @param originalIds
     * @param currentIds
     * @return
     */
    @Override
    public String getAddedOrDeleteIds(String type, String originalIds, String currentIds) {
        List<String> originalIdList;
        if (Strings.isNullOrEmpty(originalIds)) {
            originalIdList = new ArrayList<>();
        } else {
            originalIdList = new ArrayList<>(Splitter.on(",").splitToList(originalIds));
        }
        List<String> currentIdList;
        if (Strings.isNullOrEmpty(currentIds)) {
            currentIdList = new ArrayList();
        } else {
            currentIdList = new ArrayList<>(Splitter.on(",").splitToList(currentIds));
        }

        List<String> mixedIdList = new ArrayList<>();
        for (String eachOriginalId : originalIdList) {
            for (String eachCurrentId : currentIdList) {
                if (eachOriginalId.equals(eachCurrentId)) {
                    mixedIdList.add(eachCurrentId);
                }
            }
        }

        if ("removed".equals(type)) {
            for (String eachStr : mixedIdList) {
                originalIdList.remove(eachStr);
            }
            return Joiner.on(",").join(originalIdList);
        } else if ("added".equals(type)) {
            for (String eachStr : mixedIdList) {
                currentIdList.remove(eachStr);
            }
            return Joiner.on(",").join(currentIdList);
        }

        return null;
    }

    @Override
    public List<String> findAccountRoleIds(String tenantId, String accountId) {
        return rbacAccountService.findAccountRoles(tenantId, accountId);
    }

    @Override
    public List<String> findAccountDeptIds(String tenantId, String accountId) {
        List<DynaBean> accountDeptList = metaService.select("JE_RBAC_ACCOUNTDEPT", ConditionsWrapper.builder()
                .eq("ACCOUNTDEPT_ACCOUNT_ID", accountId));
        if (accountDeptList == null || accountDeptList.isEmpty()) {
            return null;
        }

        List<String> deptIdList = new ArrayList<>();
        for (DynaBean eachBean : accountDeptList) {
            deptIdList.add(eachBean.getStr("ACCOUNTDEPT_DEPT_ID"));
        }

        return deptIdList;
    }

    @Override
    public List<String> findAccountOrgIds(String accountId) {
        List<String> orgIdList = new ArrayList<>();
        DynaBean accountBean = metaService.selectOne("JE_RBAC_ACCOUNT", ConditionsWrapper.builder()
                .eq("JE_RBAC_ACCOUNT_ID", accountId));
        orgIdList.add(accountBean.getStr("SY_ORG_ID"));
        return orgIdList;
    }

    @Override
    public List<DynaBean> findBatchAccount(String tableCode, String ids, String column) {
        List<String> idList = new ArrayList<>(Splitter.on(",").splitToList(ids));
        return metaService.select(tableCode, ConditionsWrapper.builder().in(column, idList));
    }

    @Override
    public JSONTreeNode getAccountDeptTreeNode(List<Map<String, Object>> deptMapList) {
        JSONTreeNode rootNode = TreeUtil.buildRootNode();
        for (Map<String, Object> eachMapBean : deptMapList) {
            JSONTreeNode node = buildTreeNode(eachMapBean);
            rootNode.getChildren().add(node);
        }
        return rootNode;
    }

    public JSONTreeNode buildTreeNode(Map<String, Object> mapBean) {
        JSONTreeNode node = new JSONTreeNode();
        node.setId(mapBean.get("id") + "");
        node.setText(mapBean.get("name") + "");
        node.setIcon(IconType.TCONTYPE_DEPART.getVal());
        return node;
    }

}
